﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Input;
namespace Gronia.WPF.Controls
{
    public class ConnectionChild : Control
    {
        static ConnectionChild()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ConnectionChild), new FrameworkPropertyMetadata(typeof(ConnectionChild)));
        }

        public ConnectionChild()
        {
            InputPoints = new ObservableCollection<ConnectPoint>();
            OutputPoints = new ObservableCollection<ConnectPoint>();
            InputPoints.CollectionChanged += Inputs_Changed;
            OutputPoints.CollectionChanged += Outputs_Changed;

            Loaded += delegate
            {
                Window w = Window.GetWindow(this);
                MouseMove += OnMouseMove;
                MouseDown += delegate { tempPoint = Mouse.GetPosition((UIElement)Parent); moving = true; };
                w.MouseUp += delegate { moving = false; };
            };
        }

        private Point tempPoint = new Point(-1, -1);
        private bool moving = false;
        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (moving)
            {
                Point newTemp = Mouse.GetPosition((UIElement)Parent);
                Vector diff = newTemp - tempPoint;
                if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                {
                    Position = new Point(Position.X + diff.X, Position.Y + diff.Y);
                    tempPoint = newTemp;
                }
                else
                {
                    if (Math.Abs(diff.X) > 10 && Math.Abs(diff.Y) > 10)
                    {
                        Position = new Point(Position.X + diff.X, Position.Y + diff.Y);
                        tempPoint = newTemp;
                    }
                    else if (Math.Abs(diff.X) > 10)
                    {
                        Position = new Point(Position.X + diff.X, Position.Y);
                        newTemp.Y -= diff.Y;
                        tempPoint = newTemp;
                    }
                    else if (Math.Abs(diff.Y) > 10)
                    {
                        Position = new Point(Position.X, Position.Y + diff.Y);
                        newTemp.X -= diff.X;
                        tempPoint = newTemp;
                    }
                }
            }
        }

        #region Properties

        public ObservableCollection<ConnectPoint> InputPoints
        {
            get { return (ObservableCollection<ConnectPoint>)GetValue(InputPointsProperty); }
            set { SetValue(InputPointsProperty, value); }
        }

        public ObservableCollection<ConnectPoint> OutputPoints
        {
            get { return (ObservableCollection<ConnectPoint>)GetValue(OutputPointsProperty); }
            set { SetValue(OutputPointsProperty, value); }
        }

        public Point Position
        {
            get { return (Point)GetValue(PositionProperty); }
            set { SetValue(PositionProperty, value); }
        }

        #endregion

        #region Dependency Properties

        public static readonly DependencyProperty InputPointsProperty = DependencyProperty.Register("InputPoints", typeof(ObservableCollection<ConnectPoint>), typeof(ConnectionChild), new PropertyMetadata(null, new PropertyChangedCallback(InputPoints_ValueChanged)));
        public static readonly DependencyProperty OutputPointsProperty = DependencyProperty.Register("OutputPoints", typeof(ObservableCollection<ConnectPoint>), typeof(ConnectionChild), new PropertyMetadata(null, new PropertyChangedCallback(OutputPoints_ValueChanged)));
        public static readonly DependencyProperty PositionProperty = DependencyProperty.Register("Position", typeof(Point), typeof(ConnectionChild), new PropertyMetadata(new Point(0, 0), new PropertyChangedCallback(Position_ValueChanged)));

        #endregion

        #region Value Changed

        private static void InputPoints_ValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ConnectionChild me = sender as ConnectionChild;
            if (e.NewValue != null)
            {
                ObservableCollection<ConnectPoint> points = e.NewValue as ObservableCollection<ConnectPoint>;
                points.CollectionChanged += me.Inputs_Changed;
            }

            if (e.OldValue != null)
            {
                ObservableCollection<ConnectPoint> points = e.OldValue as ObservableCollection<ConnectPoint>;
                points.CollectionChanged -= me.Inputs_Changed;
            }
        }

        private static void OutputPoints_ValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ConnectionChild me = sender as ConnectionChild;
            if (e.NewValue != null)
            {
                ObservableCollection<ConnectPoint> points = e.NewValue as ObservableCollection<ConnectPoint>;
                points.CollectionChanged += me.Outputs_Changed;
            }

            if (e.OldValue != null)
            {
                ObservableCollection<ConnectPoint> points = e.OldValue as ObservableCollection<ConnectPoint>;
                points.CollectionChanged -= me.Outputs_Changed;
            }
        }

        private static void Position_ValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ConnectionChild me = sender as ConnectionChild;
            Canvas.SetLeft(me, me.Position.X);
            Canvas.SetTop(me, me.Position.Y);
            if (me.Parent != null)
            {
                ((ConnectContainer)((Canvas)(me.Parent)).Parent).Redraw(me);
            }
        }

        #endregion

        private Dictionary<ConnectPoint, Path> Paths = new Dictionary<ConnectPoint, Path>();

        private void Inputs_Changed(object sender, NotifyCollectionChangedEventArgs e)
        {

        }

        private void Outputs_Changed(object sender, NotifyCollectionChangedEventArgs e)
        {

        }

        public void Connect(ConnectPoint From, ConnectPoint To)
        {
            ((ConnectContainer)((Canvas)Parent).Parent).Connect(From, To);
        }

        public void Disconnect(ConnectPoint Point)
        {
            ((ConnectContainer)((Canvas)Parent).Parent).Disconnect(Point);
        }
    }
}